package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.imageio.ImageIO;
import javax.sound.midi.Instrument;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Synthesizer;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDesktopPane;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.filechooser.FileFilter;

/**
 * 
 * @author wolgrand
 */
public class Gui extends JFrame {

	// Declaração das variáveis de classe:
	private JDesktopPane desktop;
	private JMenuBar barra;
	private JMenu arquivo;
	private JMenu histograma;
	private JMenu deformacoes;
	private JMenuItem expadeHistograma;
	private JMenuItem abrir;
	private JMenuItem exportar;
	private JMenuItem sair;
	private JMenuItem rotacaoNormal;
	private JList listaInstrumentos;
	private JList instrumentosSelecionados;
	private Box boxMaior = Box.createHorizontalBox();
	private Box boxA = Box.createVerticalBox();
	private Box boxB = Box.createVerticalBox();
	private Box boxC = Box.createVerticalBox();
	private Box boxButtons = Box.createVerticalBox();
	private String[] instrumentos;
	private JPanel midiFrame;
	private JButton addButton;
	private JButton removeButton;
	private JButton stopButton;
	private JButton playButton;
	private JButton exportarMid;
	private JButton executarPorArquivo;
	private JLabel listaDeInstrumentos;
	private JLabel listaDeInstSelecionados;
	private JComboBox comboBoxMapeamentos;
	private int[] listaInstrumentosSelecionados;

	// Construtor configura a GUI
	public Gui() {

		super("Sinestesia");

		inicializa();

		inicializalistaInstrumentos();

		// Configura o ouvinte para o item de menu newFrame
		abrir.addActionListener(

		new ActionListener()// classe interna anonima
				{
					// exibe a nova janela interna
					public void actionPerformed(ActionEvent event) {
						JFileChooser fc = new JFileChooser();
						fc.setApproveButtonText("Abrir");
						fc.setDialogTitle("Abrir imagem");
						fc.setDialogType(JFileChooser.OPEN_DIALOG);
						fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
						fc.setAcceptAllFileFilterUsed(false);
						fc.setCurrentDirectory(new File("."));
						fc.setFileFilter(new FileFilter() {
							public boolean accept(File f) {
								if (!f.isFile())
									return true;
								else
									return f.getName().toLowerCase().endsWith(
										".png")
										|| f.getName().toLowerCase().endsWith(
												".bmp")
										|| f.getName().toLowerCase().endsWith(
												".jpg");
							}

							public String getDescription() {
								return "Imagens [PNG, BMP, JPG]";
							}
						});
						fc.setMultiSelectionEnabled(false);
						if (fc.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) {
							return;
						}

						String nome = fc.getSelectedFile().getAbsolutePath();

						MeuFrameInterno frame = new MeuFrameInterno(nome);
						desktop.add(frame); // Anexa o frame interno
						frame.setVisible(true); // mostra o frame interno
						frame.pack();// Configura o quadro interno de acordo com
						// o tamanho do conteudo

					} // fim do método actionPerformed
				} // fim da classe interna anonima
				);// fim da chama para addActionListener

		exportar.addActionListener(

		new ActionListener()// classe interna anonima
				{
					public void actionPerformed(ActionEvent event) {

						BufferedImage imagem = null;
						MeuFrameInterno frame = (MeuFrameInterno) desktop
								.getSelectedFrame();

						try {
							imagem = frame.getPanel().getImagem();
						} catch (NullPointerException e) {
							JOptionPane.showMessageDialog(null,
									"Não há nenhuma imagem aberta!", "",
									JOptionPane.ERROR_MESSAGE);
							return;
						}
						JFileChooser fc = new JFileChooser();
						fc.setApproveButtonText("Salvar");
						fc.setDialogTitle("Salvar Imagem");
						fc.setDialogType(JFileChooser.OPEN_DIALOG);
						fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
						fc.setAcceptAllFileFilterUsed(false);
						fc.setCurrentDirectory(new File("."));
						fc.setFileFilter(new FileFilter() {
							public boolean accept(File f) {
								if (!f.isFile())
									return true;
								return f.getName().toLowerCase().endsWith(
										".jpg");
							}

							public String getDescription() {
								return "jpg";
							}
						});
						fc.setFileFilter(new FileFilter() {
							public boolean accept(File f) {
								if (!f.isFile())
									return true;
								return f.getName().toLowerCase().endsWith(
										".png");
							}

							public String getDescription() {
								return "png";
							}
						});
						fc.setFileFilter(new FileFilter() {
							public boolean accept(File f) {
								if (!f.isFile())
									return true;
								return f.getName().toLowerCase().endsWith(
										".bmp");
							}

							public String getDescription() {
								return "bmp";
							}
						});
						fc.setMultiSelectionEnabled(false);
						if (fc.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) {
							return;
						}

						String nome = fc.getSelectedFile().getName();
						String tipo = fc.getFileFilter().getDescription();
						File arquivo = new File(nome + "." + tipo);

						try {
							ImageIO.write(imagem, tipo, arquivo);
						} catch (IOException ex) {
							Logger.getLogger(Gui.class.getName()).log(
									Level.SEVERE, null, ex);
						}

					} // fim do método actionPerformed
				} // fim da classe interna anonima

				);

		sair.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				System.exit(0);
			}
		});

		expadeHistograma.addActionListener(

		new ActionListener()// classe interna anonima
				{
					public void actionPerformed(ActionEvent event) {

						MeuFrameInterno frame = (MeuFrameInterno) desktop
								.getSelectedFrame();
						BufferedImage imagem;

						try {
							imagem = frame.getPanel().getImagem();
						} catch (NullPointerException e) {
							JOptionPane.showMessageDialog(null,
									"N�o h� nenhuma imagem selecionada!", "",
									JOptionPane.ERROR_MESSAGE);
							return;
						}

						WritableRaster raster = imagem.getRaster();
						// Filtros.expansaoHistograma(raster);
						frame.getPanel().setImagem(imagem);
						frame.pack();

					} // fim do método actionPerformed
				} // fim da classe interna anonima

				);

		rotacaoNormal.addActionListener(

		new ActionListener()// classe interna anonima
				{
					public void actionPerformed(ActionEvent event) {

						MeuFrameInterno frame = (MeuFrameInterno) desktop
								.getSelectedFrame();
						BufferedImage imagem;

						try {
							imagem = frame.getPanel().getImagem();
						} catch (NullPointerException e) {
							JOptionPane.showMessageDialog(null,
									"N�o h� nenhuma imagem selecionada!", "",
									JOptionPane.ERROR_MESSAGE);
							return;
						}

						String con = JOptionPane
								.showInputDialog("Digite o numero de centros rotações a ser selecionado:");
						int numeroDePontos = Integer.parseInt(con);
						frame.getPanel().setEstado(1);
						frame.getPanel().setNumeroDePontos(numeroDePontos);
						frame.pack();

					} // fim do método actionPerformed
				} // fim da classe interna anonima

				);

		addButton.addActionListener(new ActionListener()// classe interna
				// anonima
				{
					public void actionPerformed(ActionEvent event) {

						// Carrega os valores selecionados no box de instrumentos selecionados:
						instrumentosSelecionados.setListData(listaInstrumentos
								.getSelectedValues());
						
						// Pega os valores dos instrumentos selecionados pelo usuário para o mapeamento: 
						listaInstrumentosSelecionados = new int[listaInstrumentos
								.getSelectedIndices().length];
						listaInstrumentosSelecionados = listaInstrumentos
								.getSelectedIndices();
					}
				});

		removeButton.addActionListener(new ActionListener()
				{
					public void actionPerformed(ActionEvent event) {
						int[] selectedIndexes = instrumentosSelecionados.getSelectedIndices();
						System.out.println("Indexes: " + selectedIndexes.length);
						for (int i = 0 ; i < selectedIndexes.length ; i++)
							instrumentosSelecionados.remove(selectedIndexes[i]-1);
						instrumentosSelecionados.validate();
					}
				});

		stopButton.addActionListener(new ActionListener()// classe interna
				// anonima
				{
					public void actionPerformed(ActionEvent event) {
						// player.parar();
					}
				});

		playButton.addActionListener(new ActionListener()// classe interna
				// anonima
				{
					public void actionPerformed(ActionEvent event) {

						MeuFrameInterno frame = (MeuFrameInterno) desktop
								.getSelectedFrame();
						BufferedImage imagem;

						try {
							imagem = frame.getPanel().getImagem();
						} catch (NullPointerException e) {
							JOptionPane.showMessageDialog(null,
									"N�o h� nenhuma imagem selecionada!", "",
									JOptionPane.ERROR_MESSAGE);
							return;
						}

						WritableRaster raster = imagem.getRaster();
						if (listaInstrumentosSelecionados == null) {
							JOptionPane.showMessageDialog(null,
									"Escolha os Instrumentos!", "",
									JOptionPane.ERROR_MESSAGE);
							return;
						}

						switch (comboBoxMapeamentos.getSelectedIndex()) {
						case 0: {
							JOptionPane.showMessageDialog(null,
									"Escolha o tipo mapemanto Imagem-Audio",
									"", JOptionPane.ERROR_MESSAGE);
							break;
						}
						case 1: {
							// player =
							// Mapeamentos.mapeamentoPorLinha(raster,listaInstrumentosSelecionados);
							break;
						}
						case 2: {
							// player =
							// Mapeamentos.mapeamentoPorColuna(raster,listaInstrumentosSelecionados);
							break;
						}
						case 3: {
							// player = Mapeamentos.mapeamentoZeta(raster,
							// fator,listaInstrumentosSelecionados[0]);
							break;
						}
						case 4: {
							ArrayList<Integer> list = new ArrayList<Integer>();
							for (int i = 0; i < listaInstrumentosSelecionados.length; i++) {
								list.add(listaInstrumentosSelecionados[i]);
							}
							// player = Mapeamentos.mapeamentoTheta(raster,
							// fator, list );
							break;
						}
						case 5: {
							ArrayList<Integer> list = new ArrayList<Integer>();
							for (int i = 0; i < listaInstrumentosSelecionados.length; i++) {
								list.add(listaInstrumentosSelecionados[i]);
							}
							// player = Mapeamentos.mapeamentoIota(raster,
							// fator, list );
							break;
						}
						}
						// player.executa();
					}
				});

		exportarMid.addActionListener(new ActionListener()// classe interna
				// anonima
				{
					public void actionPerformed(ActionEvent event) {

						MeuFrameInterno frame = (MeuFrameInterno) desktop
								.getSelectedFrame();
						BufferedImage imagem;

						try {
							imagem = frame.getPanel().getImagem();
						} catch (NullPointerException e) {
							JOptionPane.showMessageDialog(null,
									"Não há nenhuma imagem selecionada!", "",
									JOptionPane.ERROR_MESSAGE);
							return;
						}

						WritableRaster raster = imagem.getRaster();
						if (listaInstrumentosSelecionados == null) {
							JOptionPane.showMessageDialog(null,
									"Escolha os Instrumentos!", "",
									JOptionPane.ERROR_MESSAGE);
							return;
						}

						switch (comboBoxMapeamentos.getSelectedIndex()) {
						case 0: {
							JOptionPane.showMessageDialog(null,
									"Escolha o tipo mapemanto Imagem-Audio",
									"", JOptionPane.ERROR_MESSAGE);
							break;
						}
						case 1: {
							// player =
							// Mapeamentos.mapeamentoPorLinha(raster,listaInstrumentosSelecionados);
							break;
						}
						case 2: {
							// player =
							// Mapeamentos.mapeamentoPorColuna(raster,listaInstrumentosSelecionados);
							break;
						}
						case 3: {
							// player = Mapeamentos.mapeamentoZeta(raster,
							// fator,listaInstrumentosSelecionados[0]);
							break;
						}
						case 4: {
							ArrayList<Integer> list = new ArrayList<Integer>();
							for (int i = 0; i < listaInstrumentosSelecionados.length; i++) {
								list.add(listaInstrumentosSelecionados[i]);
							}
							// player = Mapeamentos.mapeamentoTheta(raster,
							// fator, list );
							break;
						}
						case 5: {
							String con = JOptionPane
									.showInputDialog("Digite o fator de compress�o para o mapeamento:");
							int fator = Integer.parseInt(con);
							ArrayList<Integer> list = new ArrayList<Integer>();
							for (int i = 0; i < listaInstrumentosSelecionados.length; i++) {
								list.add(listaInstrumentosSelecionados[i]);
							}
							// player = Mapeamentos.mapeamentoIota(raster,
							// fator, list );
							break;
						}
						}

						JFileChooser fc = new JFileChooser();
						fc.setApproveButtonText("Exportar");
						fc.setDialogTitle("Exportar para MMF");
						fc.setDialogType(JFileChooser.OPEN_DIALOG);
						fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
						fc.setAcceptAllFileFilterUsed(false);
						fc.setCurrentDirectory(new File("."));
						fc.setFileFilter(new FileFilter() {
							public boolean accept(File f) {
								if (!f.isFile())
									return true;
								return f.getName().toLowerCase().endsWith(
										".mmf");
							}

							public String getDescription() {
								return "mmf";
							}
						});

						fc.setMultiSelectionEnabled(false);
						if (fc.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) {
							return;
						}

						String tipo = fc.getFileFilter().getDescription();
						String arquivo = "." + tipo;

						// try{
						// new Writer(fc.getSelectedFile().getPath(),arquivo,
						// player.getNotasFaixas(), player.getInstrumento());
						// }catch(Exception e){
						// JOptionPane.showMessageDialog(null,"N�o h� nenhum mapeamento carregado!","",JOptionPane.ERROR_MESSAGE);
						// }
					} // fim do método actionPerformed
				} // fim da classe interna anonima
				);

		executarPorArquivo.addActionListener(new ActionListener()// classe
				// interna
				// anonima
				{
					public void actionPerformed(ActionEvent event) {

						JFileChooser fc = new JFileChooser();
						fc.setApproveButtonText("Executar MMF");
						fc.setDialogTitle("Abrir arquivo MMF");
						fc.setDialogType(JFileChooser.OPEN_DIALOG);
						fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
						fc.setAcceptAllFileFilterUsed(false);
						fc.setCurrentDirectory(new File("."));
						fc.setFileFilter(new FileFilter() {
							public boolean accept(File f) {
								if (!f.isFile())
									return true;
								return f.getName().toLowerCase().endsWith(
										".mmf");
							}

							public String getDescription() {
								return "MMF";
							}
						});
						fc.setMultiSelectionEnabled(false);
						if (fc.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) {
							return;
						}

						// Reader reader = new
						// Reader(fc.getSelectedFile().getAbsolutePath());
						// // Inicializa o player:
						// player = new Player(reader.getNotasFaixas(),
						// reader.getInstrumentos());
						//							 
						// player.executa();

						// o tamanho do conteudo

					} // fim do método actionPerformed
				} // fim da classe interna anonima
				);

	}// fim do construtor

	private void inicializa() {

		desktop = new JDesktopPane();// cria o painel de área de trabalho
		desktop.setBackground(new Color(50, 50, 50));
		getContentPane().add(desktop);// adiciona painel de area de trabalho ao
										// frame
		barra = new JMenuBar();// Cria a barra de menus
		arquivo = new JMenu("Arquivo");// cria o menu adicionar
		histograma = new JMenu("Histograma");
		deformacoes = new JMenu("Girar");
		exportarMid = new JButton("Exportar(MID)");
		expadeHistograma = new JMenuItem("Expandir Histograma");
		abrir = new JMenuItem("Abrir");
		exportar = new JMenuItem("Salvar");
		sair = new JMenuItem("Sair");
		rotacaoNormal = new JMenuItem("Rotação Normal");
		listaInstrumentos = new JList();
		instrumentos = new String[129];
		midiFrame = new JPanel();
		addButton = new JButton("Adicionar");
		removeButton = new JButton("Remover");
		stopButton = new JButton("Parar               ");
		playButton = new JButton("Play                  ");
		executarPorArquivo = new JButton("Executar do Arquivo");
		String[] nomesMapeamentos = { "-> Selecione o Mapeamento <-",
				"Mapeamento por Linha", "Mapeamento por Coluna",
				"Mepeamento Zeta", "Mapeamento Theta", "Mapeamento Tota" };
		comboBoxMapeamentos = new JComboBox(nomesMapeamentos);
		comboBoxMapeamentos.setMaximumSize(new Dimension(200, 30));

		arquivo.add(abrir); // Adiciona um novo item do frame ao menu Add
		arquivo.add(exportar);
		arquivo.add(sair);
		histograma.add(expadeHistograma);
		deformacoes.add(rotacaoNormal);
		barra.add(arquivo); // Adiciona o menu add a barra de menus
		barra.add(histograma);
		barra.add(deformacoes);
		setJMenuBar(barra); // configura a barra de menus para este aplicativo
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setSize(1280, 600);
		setVisible(true);
	}

	private void inicializalistaInstrumentos() {

		midiFrame.setBounds(0, 0, 1000, 150);

		Synthesizer synthesizer = null;
		try {
			synthesizer = MidiSystem.getSynthesizer();
			synthesizer.open();
		} catch (MidiUnavailableException e) {
			e.printStackTrace();
		}

		Instrument[] instruments = synthesizer.getAvailableInstruments();

		for (int i = 0; i < 128; i++)
			instrumentos[i] = "[" + i + "] - " + instruments[i].getName();

		instrumentosSelecionados = new JList();
		listaInstrumentos.setModel(new javax.swing.DefaultComboBoxModel(
				instrumentos));
		listaInstrumentos.setFixedCellHeight(15);
		instrumentosSelecionados.setFixedCellWidth(30);
		listaInstrumentos
				.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		listaDeInstrumentos = new JLabel("Lista de Instrumentos:",
				SwingConstants.LEFT);
		boxA.add(listaDeInstrumentos, BorderLayout.NORTH);
		boxA.add(new JScrollPane(listaInstrumentos), BorderLayout.CENTER);
		listaDeInstSelecionados = new JLabel("Instrumentos Selecionados:",
				SwingConstants.LEFT);
		instrumentosSelecionados.setFixedCellHeight(15);
		instrumentosSelecionados.setFixedCellWidth(30);
		boxB.add(listaDeInstSelecionados, BorderLayout.NORTH);
		boxB
				.add(new JScrollPane(instrumentosSelecionados),
						BorderLayout.CENTER);
		boxC.add(comboBoxMapeamentos);
		boxC.add(new JLabel("      "));
		boxC.add(playButton);
		boxC.add(stopButton);
		boxC.add(exportarMid);
		boxC.add(executarPorArquivo);
		boxMaior.add(boxA);
		boxButtons.add(addButton);
		boxButtons.add(new JLabel("     "));
		boxButtons.add(removeButton);
		boxMaior.add(boxButtons);
		boxMaior.add(boxB);
		boxMaior.add(new JLabel("     "));
		boxMaior.add(new JLabel("     "));
		boxMaior.add(boxC);
		midiFrame.add(boxMaior);
		midiFrame.setVisible(true);
		desktop.add(midiFrame, BorderLayout.WEST);
	}
}